package com.xlongwei.session;

import java.util.HashSet;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.exceptions.JedisException;

public class JedisUtil {
	private static final Logger log = LoggerFactory.getLogger(JedisUtil.class);

	public static<V> V exec(JedisPool pool, JedisSentinelPool sentinel, JedisCluster cluster, Callback<V> callback) {
		Jedis jedis = jedis(pool, sentinel, cluster);
		try {
			return callback.execute(jedis);
		}catch(JedisException je){
			jedis.close();
			jedis = jedis(pool, sentinel, cluster);
			try{
				return callback.execute(jedis);
			}catch(Exception e) {
				log.debug(e.getMessage());
			}
		}catch(Exception e){
			log.debug(e.getMessage());
		}finally {
			jedis.close();
		}
		return null;
	}
	
	public static Jedis jedis(JedisPool pool, JedisSentinelPool sentinel, JedisCluster cluster) {
		if(pool != null) {
			return pool.getResource();
		}else if(cluster != null) {
			return new JedisWrapper(cluster);
		}else {
			return sentinel.getResource();
		}
	}
	
	public static void close(JedisPool pool, JedisSentinelPool sentinel, JedisCluster cluster) {
		if(pool != null) {
			pool.close();
		}else if(cluster != null) {
			try {
				cluster.close();
			}catch(Exception e) {
				log.debug(e.getMessage());
			}
		}else if(sentinel != null) {
			sentinel.close();
		}
	}
	
	public static String firstNonBlank(String ... strs) {
		if(strs==null || strs.length==0) {
			return null;
		}
		for(String str : strs) {
			if(!isBlank(str)) {
				return str.trim();
			}
		}
		return "";
	}
	
	public static Set<HostAndPort> nodes(String hostAndPorts) {
		if(!JedisUtil.isBlank(hostAndPorts)) {
			Set<HostAndPort> nodes = new HashSet<HostAndPort>();
			for(String hostAndPort : hostAndPorts.split("[,]")) {
				if(!JedisUtil.isBlank(hostAndPort)) {
					String[] split = hostAndPort.split("[:]");
					if(split!=null && split.length==2) {
						nodes.add(new HostAndPort(split[0], Integer.parseInt(split[1])));
					}else {
						log.debug("bad HostAndPort="+hostAndPort);
					}
				}
			}
			return nodes;
		}
		return null;
	}
	
	public static Set<String> sentinels(Set<HostAndPort> nodes) {
		Set<String> sentinels = new HashSet<String>();
		for(HostAndPort hostAndPort : nodes) {
			sentinels.add(hostAndPort.toString());
		}
		return sentinels;
	}
	
	public static boolean isBlank(String str) {
		return str==null || str.trim().length()==0;
	}
	
	public interface Callback<V> {
		V execute(Jedis jedis);
	}
	
	static class JedisWrapper extends Jedis {
		JedisCluster cluster;
		JedisWrapper(JedisCluster cluster) { this.cluster = cluster; }
		public byte[] get(byte[] key) { return cluster.get(key); }
		public Long del(byte[] key) { return cluster.del(key); }
		public String setex(byte[] key, int seconds, byte[] value) { return cluster.setex(key, seconds, value); }
		public Long expire(String key, int seconds) { return cluster.expire(key, seconds); }
		public void close() { }
	}
}
